package org.simtube.gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.swing.*;

import org.simtube.query.QueryController;
import org.simtube.util.DocWithId;

public class SimTube extends JFrame implements ActionListener {

	private static final long serialVersionUID = -6506248452450913845L;
	
	// Three main panels
	
	private JPanel inputPanel;
	private JPanel docListPanel;
	private JPanel docViewPanel;
	
	// Components in the left module
	
	private JLabel logoLabel;
	private JButton testBenchButton;
	private JLabel statusLabel;
	private JLabel inputLabel;
	private JScrollPane inputScrollPane;
	private JTextArea inputTextArea;
	private JButton submitButton;
	private JButton tryAgainButton;
	private JButton loadButton;
	private JButton findMoreButton;
	private JLabel relevantLabel;
	private JLabel irrelevantLabel;
	
	// Components in the central module
	
	private JPanel[] docItemPanel;
	private JLabel[] docItemTitleLabel;
	private JLabel[] docItemContentLabel;
	private JButton[] docItemViewButton;
	private JButton[] docItemRelevantButton;
	private JButton[] docItemIrrelevantButton;
	private JLabel[] docItemScoreLabel;
	
	// Components in the right module
	
	private JLabel viewLabel;
	private JTextArea viewTextArea;
	private JScrollPane viewScrollPane;
	private JButton viewRelevantButton;
	private JButton viewIrrelevantButton;
	
	// Some arguments
	
	private int nResults;
	private QueryController qc;
	private DocWithId[] result;
	private int current;
	private LinkedList<Integer> relevantList;
	private LinkedList<Integer> irrelevantList;
	
	public SimTube(String title) {
		super(title);
		
		initArguments();
		
		loadComponents();
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(1000, 650);
		this.setVisible(true);
		
		new InitThread(qc, statusLabel).start();
	}
	
	public void initArguments() {
		nResults = 10;
		qc = new QueryController();
		// qc = null;
		current = -1;
		relevantList = new LinkedList<Integer>();
		irrelevantList = new LinkedList<Integer>();
		
		result = new DocWithId[nResults];
		
		for(int i = 0; i < nResults; i++) {
			result[i] = new DocWithId(getDefaultContent(), i, 0);
			result[i].setDocMatId(-1);
		}
	}
	
	public void loadComponents() {
		
		// left part of the frame
		
		inputPanel = new JPanel(new BorderLayout());
		
		JPanel firstPanel = new JPanel(new GridLayout(1, 2, 1, 1)); 
		logoLabel = new JLabel("LOGO!");
		testBenchButton = new JButton("Benchmark Test!");
		testBenchButton.addActionListener(this);
		
		firstPanel.add(logoLabel);
		firstPanel.add(testBenchButton);
		
		statusLabel = new JLabel("Status: Nothing");
		inputLabel = new JLabel("Please input your text here: ");
		inputTextArea = new JTextArea(25, 20);
		// inputTextArea.setLineWrap(true);
		
		inputScrollPane = new JScrollPane(inputTextArea);
		
		JPanel upperPanel = new JPanel(new GridLayout(3, 1, 3, 3));
		upperPanel.add(firstPanel);
		upperPanel.add(statusLabel);
		upperPanel.add(inputLabel);
		
		JPanel lowerPanel = new JPanel(new GridLayout(3, 1, 3, 3));
		relevantLabel = new JLabel("Relevant docs: ");
		irrelevantLabel = new JLabel("Irrelevant docs: ");
		lowerPanel.add(relevantLabel);
		lowerPanel.add(irrelevantLabel);
		
		submitButton = new JButton("Search!");
		submitButton.addActionListener(this);
		tryAgainButton = new JButton("Try Again!");
		tryAgainButton.addActionListener(this);
		loadButton = new JButton("Open!");
		loadButton.addActionListener(this);
		
		JPanel btnPanel = new JPanel(new GridLayout(1, 3, 3, 1));
		btnPanel.add(loadButton);
		btnPanel.add(submitButton);
		btnPanel.add(tryAgainButton);
		
		lowerPanel.add(btnPanel);
		
		inputPanel.add(upperPanel, BorderLayout.NORTH);
		inputPanel.add(inputScrollPane, BorderLayout.CENTER);
		inputPanel.add(lowerPanel, BorderLayout.SOUTH);
		
		// central part of the frame
		
		docListPanel = new JPanel(new GridLayout(nResults + 1, 1, 3, 3));
		docItemPanel = new JPanel[nResults + 1];
		docItemTitleLabel = new JLabel[nResults];
		docItemContentLabel= new JLabel[nResults];
		docItemViewButton = new JButton[nResults];
		docItemRelevantButton = new JButton[nResults];
		docItemIrrelevantButton = new JButton[nResults];
		docItemScoreLabel = new JLabel[nResults];
		
		for(int i = 0; i < nResults; i++) {
			docItemPanel[i] = new JPanel(new GridLayout(3, 1, 1, 1));
			docItemTitleLabel[i] = new JLabel("Doc " + result[i].getId());
			docItemContentLabel[i] = new JLabel(
					result[i].getContent().substring(
							0, 100 > result[i].getContent().length() ?
									result[i].getContent().length() : 100));
			docItemViewButton[i] = new JButton("View!");
			docItemViewButton[i].addActionListener(this);
			docItemRelevantButton[i] = new JButton("Relevant!");
			docItemRelevantButton[i].addActionListener(this);
			docItemIrrelevantButton[i] = new JButton("Irrelevant!");
			docItemIrrelevantButton[i].addActionListener(this);
			docItemScoreLabel[i] = new JLabel("Score: ");
			docItemScoreLabel[i].setHorizontalAlignment(JLabel.LEFT);
			
			docItemPanel[i].add(docItemTitleLabel[i]);
			docItemPanel[i].add(docItemContentLabel[i]);
			
			JPanel tpanel = new JPanel(new GridLayout(1, 4, 3, 1));
			tpanel.add(docItemScoreLabel[i]);
			tpanel.add(docItemIrrelevantButton[i]);
			tpanel.add(docItemRelevantButton[i]);
			tpanel.add(docItemViewButton[i]);
			
			docItemPanel[i].add(tpanel);
			
			docListPanel.add(docItemPanel[i]);
		}
		
		docItemPanel[nResults] = new JPanel();
		findMoreButton = new JButton("Find More!");
		findMoreButton.addActionListener(this);
		docItemPanel[nResults].add(findMoreButton);
		
		docListPanel.add(docItemPanel[nResults]);
		
		// right part of the frame
		
		docViewPanel = new JPanel(new BorderLayout());
		
		viewLabel = new JLabel("You are viewing text: ");
		viewTextArea = new JTextArea(25, 20);
		viewScrollPane = new JScrollPane(viewTextArea);
		
		docViewPanel.add(viewLabel, BorderLayout.NORTH);
		docViewPanel.add(viewScrollPane, BorderLayout.CENTER);
		
		JPanel vpanel = new JPanel(new GridLayout(1, 3, 3, 1));
		vpanel.add(new JPanel());
		viewRelevantButton = new JButton("Relevant!");
		viewRelevantButton.addActionListener(this);
		viewIrrelevantButton = new JButton("Irrelevant!");
		viewIrrelevantButton.addActionListener(this);
		vpanel.add(viewIrrelevantButton);
		vpanel.add(viewRelevantButton);
		
		docViewPanel.add(vpanel, BorderLayout.SOUTH);
		
		Container c = this.getContentPane();
		c.setLayout(new BorderLayout(10, 5));
		c.add(inputPanel, BorderLayout.WEST);
		c.add(docListPanel, BorderLayout.CENTER);
		c.add(docViewPanel, BorderLayout.EAST);
	}
	
	public static void main(String[] args) {
		new SimTube("SimTube");
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		JButton btn = (JButton)(e.getSource());
		
		if(btn == loadButton) {
			loadFile();
		} else if(btn == testBenchButton) {
			testBench();
		} else if(btn == submitButton) {
			submit();
		} else if(btn == tryAgainButton) {
			tryAgain();
		} else if(btn == findMoreButton) {
			findMore();
		} else if(btn == viewRelevantButton) {
			if(!relevantList.contains(current))
				relevantList.add(current);
			if(irrelevantList.contains(current))
				irrelevantList.remove(new Integer(current));
		} else if(btn == viewIrrelevantButton) {
			if(!irrelevantList.contains(current))
				irrelevantList.add(current);
			if(relevantList.contains(current))
				relevantList.remove(new Integer(current));
		} else {
			for(int i = 0; i < nResults; i++) {
				if(btn == docItemViewButton[i]) {
					current = i;
					showDoc();
					break;
				} else if(btn == docItemRelevantButton[i]) {
					if(!relevantList.contains(i))
						relevantList.add(i);
					if(irrelevantList.contains(i))
						irrelevantList.remove(new Integer(i));
					break;
				} else if(btn == docItemIrrelevantButton[i]) {
					if(!irrelevantList.contains(i))
						irrelevantList.add(i);
					if(relevantList.contains(i))
						relevantList.remove(new Integer(i));
					break;
				}
			}
		}
		
		relevantLabel.setText("Relevant docs: " + getString(relevantList));
		irrelevantLabel.setText("Irrelevant docs: " + getString(irrelevantList));
	}

	private void testBench() {
		new BenchTestThread(qc, statusLabel).start();
	}

	private void findMore() {
		new ClusterDialog(this, "Clustering Result", qc);
	}

	private void showDoc() {
		viewTextArea.setText(result[current].getContent());
	}

	private void tryAgain() {
		
		long start = System.nanoTime();
		
		this.setStatus("Search started...");
		
		int[] relev = new int[relevantList.size()];
		Iterator<Integer> it = relevantList.iterator();
		int index = 0;
		while(it.hasNext()) relev[index++] = it.next();
		
		int[] irrelev = new int[irrelevantList.size()];
		it = irrelevantList.iterator();
		index = 0;
		while(it.hasNext()) irrelev[index++] = it.next();
		
		result = qc.feedbackQuery(nResults, relev, irrelev);
		int i = 0;
		for(i = 0; i < result.length; i++) {
			docItemTitleLabel[i].setText("Doc " + result[i].getId());
			docItemContentLabel[i].setText(result[i].getContent());
			docItemScoreLabel[i].setText("Score: " + Math.cos(result[i].getScore()));
		}
		while(i < nResults) {
			docItemTitleLabel[i].setText("Doc NaN");
			docItemContentLabel[i].setText(getDefaultContent());
		}
		relevantList.clear();
		irrelevantList.clear();
		
		long end = System.nanoTime();
		
		this.setStatus("Search finished... " + (end - start) / 1000000
				+ "ms in total");
	}

	private void submit() {
		long start = System.nanoTime();
		
		this.setStatus("Search started...");
		
		result = qc.kNNQuery(10, inputTextArea.getText());
		int i = 0;
		for(i = 0; i < result.length; i++) {
			docItemTitleLabel[i].setText("Doc " + result[i].getId());
			docItemContentLabel[i].setText(result[i].getContent());
			docItemScoreLabel[i].setText("Score: " + Math.cos(result[i].getScore()));
		}
		while(i < nResults) {
			docItemTitleLabel[i].setText("Doc NaN");
			docItemContentLabel[i].setText(getDefaultContent());
		}
		relevantList.clear();
		irrelevantList.clear();
		
		long end = System.nanoTime();
		
		this.setStatus("Search finished... " + (end - start) / 1000000
				+ "ms in total");
	}

	private void loadFile() {
		JFileChooser chooser = new JFileChooser();
		chooser.setFileFilter(null);
		int returnVal = chooser.showOpenDialog(this);
		if(returnVal == JFileChooser.APPROVE_OPTION) {
			File fin = chooser.getSelectedFile();
			try {
				BufferedReader r = new BufferedReader(new FileReader(fin));
				String line = null;
				String txt = "";
				
				while((line = r.readLine()) != null) txt += line + "\n";
				
				inputTextArea.setText(txt);
				
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private String getString(List<Integer> list) {
		String str = "";
		
		Iterator<Integer> it = list.iterator();
		boolean isFirst = true;
		while(it.hasNext()) {
			if(isFirst) {
				str += result[it.next()].getId();
				isFirst = false;
			}
			else
				str += ", " + result[it.next()].getId();
		}
		
		return str;
	}
	
	private String getDefaultContent() {
		return "No content available now...";
	}
	
	private void setStatus(String msg) {
		statusLabel.setText("Status: " + msg);
	}
}
